package com.flute.tools.timer;

import java.util.Date;
import java.util.Hashtable;

import org.apache.log4j.Logger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;

import com.flute.tools.util.DateUtil;

/**
 * 包装了quartz，对于需要timer控制的操作，只需传入该操作所在的类，以及该操作的方法名即可
 * 
 * @author Dave
 * 
 */
public class FlexTimer {
	/**
	 * 日志
	 */
	public static Logger logger = Logger.getLogger(FlexTimer.class);
	/**
	 * 多个timer任务
	 */
	private Hashtable<String, Scheduler> table;
	public static final String TASK = "task";
	private static FlexTimer ft;

	private FlexTimer() {
		this.table = new Hashtable<String, Scheduler>();
	}

	/**
	 * @return FlexTimer的单例
	 */
	public synchronized static FlexTimer getInstance() {
		if (ft == null) {
			ft = new FlexTimer();
		}

		return ft;
	}

	public boolean containsTask(String id) {
		return table.containsKey(id);
	}

	public void startTimer(String id, Object obj, String methodName,
			long interval) {
		startTimer(id, obj, methodName, interval, false);
	}

	public void startTimer(String id, Object obj, String methodName, int hour,
			int minute, boolean concurrent) {
		startTimer(id, obj, methodName, null, null, hour, minute, concurrent);
	}

	public void startTimer(String id, Object obj, String methodName,
			Class<?>[] classes, Object[] params, int hour, int minute) {
		startTimer(id, obj, methodName, classes, params, hour, minute,
				Boolean.FALSE);
	}

	public void startTimer(String id, Object obj, String methodName,
			Class<?>[] classes, Object[] params, int hour, int minute,
			boolean concurrent) {
		if (!table.containsKey(id)) {
			try {
				table.put(id, new StdSchedulerFactory().getScheduler());
				Task task = new Task();
				task.setTimerInterval(1000);
				task.setId(id);
				ReflectionMethod rm = new ReflectionMethod();
				rm.setInstance(obj);
				rm.setMethodName(methodName);
				rm.setClassName(obj.getClass().getName());
				rm.setClasses(classes);
				rm.setParams(params);
				task.setMethod(rm);
				JobDetail jobDetail = null;
				if (concurrent) {
					jobDetail = new JobDetail(id, Scheduler.DEFAULT_GROUP,
							StatefulTimerTask.class);
				} else {
					jobDetail = new JobDetail(id, Scheduler.DEFAULT_GROUP,
							StatelessTimerTask.class);
				}
				JobDataMap jdm = new JobDataMap();
				jdm.put(TASK, task);
				jobDetail.setJobDataMap(jdm);
				Trigger trigger = TriggerUtils.makeDailyTrigger(id, hour,
						minute);

				table.get(id).scheduleJob(jobDetail, trigger);
				table.get(id).start();
				logger.info("timer '" + id + "' schedule task at "
						+ DateUtil.getDateAndTimeString(new Date()));
			} catch (Exception e) {
				e.printStackTrace();
				logger.info("error occured when schedule timer '" + id + "'. ");
			}
		} else {
			logger.info("timer '" + id + "' has already scheduled the task");
		}
	}

	/**
	 * 把一个操作交给timer来控制
	 * 
	 * @param id
	 *            该操作的名称
	 * @param obj
	 *            该操作所在类
	 * @param methodName
	 *            类中的函数名
	 * @param interval
	 *            操作间隔时间
	 */
	public void startTimer(String id, Object obj, String methodName,
			Class<?>[] classes, Object[] params, long interval,
			boolean concurrent) {
		if (!table.containsKey(id)) {
			try {
				table.put(id, new StdSchedulerFactory().getScheduler());
				Task task = new Task();
				task.setTimerInterval(1000);
				task.setId(id);
				ReflectionMethod rm = new ReflectionMethod();
				rm.setInstance(obj);
				rm.setMethodName(methodName);
				rm.setClassName(obj.getClass().getName());
				rm.setClasses(classes);
				rm.setParams(params);
				task.setMethod(rm);
				JobDetail jobDetail = null;
				if (concurrent) {
					jobDetail = new JobDetail(id, Scheduler.DEFAULT_GROUP,
							StatefulTimerTask.class);
				} else {
					jobDetail = new JobDetail(id, Scheduler.DEFAULT_GROUP,
							StatelessTimerTask.class);
				}
				JobDataMap jdm = new JobDataMap();
				jdm.put(TASK, task);
				jobDetail.setJobDataMap(jdm);
				SimpleTrigger trigger = new SimpleTrigger(id, null, -1,
						interval);

				table.get(id).scheduleJob(jobDetail, trigger);
				table.get(id).start();
				logger.info("timer '" + id + "' schedule task at "
						+ DateUtil.getDateAndTimeString(new Date()));
			} catch (Exception e) {
				e.printStackTrace();
				logger.info("error occured when schedule timer '" + id + "'. ");
			}
		} else {
			logger.info("timer '" + id + "' has already scheduled the task");
		}
	}

	public void startTimer(String id, Object obj, String methodName,
			long interval, boolean concurrent) {
		startTimer(id, obj, methodName, null, null, interval, concurrent);
	}

	/**
	 * 把一个操作交给timer来控制
	 * 
	 * @param task
	 *            任务
	 */
	public void startTimer(Task task) {
		if (!table.containsKey(task.getId())) {
			try {
				table.put(task.getId(), new StdSchedulerFactory()
						.getScheduler());

				JobDetail jobDetail = new JobDetail(task.getId(),
						Scheduler.DEFAULT_GROUP, StatelessTimerTask.class);
				JobDataMap jdm = new JobDataMap();
				jdm.put(TASK, task);
				jobDetail.setJobDataMap(jdm);
				SimpleTrigger trigger = new SimpleTrigger(task.getId(), null,
						-1, task.getTimerInterval());

				table.get(task.getId()).scheduleJob(jobDetail, trigger);
				table.get(task.getId()).start();
				logger.info("timer '" + task.getId() + "' schedule task at "
						+ DateUtil.getDateAndTimeString(new Date()));
			} catch (SchedulerException e) {
				logger.info("error occured when schedule timer '"
						+ task.getId() + "'. ");
			}
		} else {
			logger.info("timer '" + task.getId()
					+ "' has already scheduled the task");
		}
	}

	/**
	 * 停止给定操作的timer
	 * 
	 * @param id
	 */
	public void stopTimer(String id) {
		Scheduler timer = table.get(id);
		if (timer != null) {
			try {
				timer.shutdown();
			} catch (SchedulerException e) {
				logger.info("fail to stop timer '" + id + "'");
			}
			logger.info("timer '" + id + "' stoped at "
					+ DateUtil.getDateAndTimeString(new Date()));
		} else {
			logger.info("timer '" + id + "' has not started yet");
		}
	}
}
